﻿// License: The MIT License (MIT) Copyright (c) 2012 Barend Gehrels

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Text;

namespace GrooveSharp
{
    static class StringUtil
    {

        private static void UpdateForPrefix(string prefix, ref string sortName)
        {
            if (sortName.StartsWith(prefix + " "))
            {
                sortName = sortName.Substring(prefix.Length + 1);
            }
        }

        private static void UpdateForInfix(string infix, ref string sortName)
        {
            string spacedInfix = " " + infix + " ";
            if (sortName.Contains(spacedInfix))
            {
                sortName = sortName.Replace(spacedInfix, " ");
            }
        }

        private static string RemoveDiacritics(string s)
        {
            // http://stackoverflow.com/questions/359827/ignoring-accented-letters-in-string-comparison
            Encoding destEncoding = Encoding.GetEncoding("iso-8859-8");

            return destEncoding.GetString(Encoding.Convert(Encoding.UTF8, destEncoding, Encoding.UTF8.GetBytes(s)));
        }

        private static string RemoveNonAlphaNumeric(string name)
        {
            string result = "";
            foreach (char c in name)
            {
                if (char.IsLetterOrDigit(c))
                {
                    result += c;
                }

            }
            return result;
        }


        /// <summary>
        /// Radically updates a string such that "the Beatles" become "BEATLES",
        /// Bob Marley & the Wailers become "BOBMARLEYWAILERS", 
        /// "Björk" will be "BJORK" etc, this removes most synonyms
        /// (with the risk that a real distinction disappears)
        /// </summary>
        public static string GetSortName(this string name)
        {
            string sortName = name.ToUpperInvariant();

            foreach (string prefix in new List<string>() { "A", "THE", "EL", "IL", "LE", "LA", "DR", "MR", "MRS", "DE", "EEN", "HET" })
            {
                UpdateForPrefix(prefix, ref sortName);
            }
            foreach (string infix in new List<string>() { "AND", "THE", "EN", "DE", "DU", "ET", "DEL", "UND" })
            {
                UpdateForInfix(infix, ref sortName);
            }

            return RemoveNonAlphaNumeric(RemoveDiacritics(sortName));
        }

        // Helper function for ExcludeBracketed, gets start/end position of start/end bracket.
        // In case of nested, they take the outer.
        private static bool Travel(string s, char starting, char ending, out int p1, out int p2)
        {
            p1 = -1;
            p2 = -1;
            int count = 0;
            for (int i = 0; i < s.Length; i++)
            {
                if (s[i] == starting)
                {
                    if (count == 0)
                    {
                        p1 = i;
                    }
                    count++;
                }
                else if (count > 0 && s[i] == ending)
                {
                    count--;
                    if (count == 0)
                    {
                        p2 = i;
                        return true;
                    }
                }
            }
            return false;
        }


        public static string ExcludeBracketed(this string name, char starting, char ending)
        {
            // "title [*]" -> "title"
            // "title [*][#]" -> "title [*]" -> "title"
            // "title [[hard]]" -> "title"
            // "title [*] extra [#]" -> title  extra [#]" -> "title  extra"             

            string result = name.Trim();
            int p1, p2;
            while(Travel(result, starting, ending, out p1, out p2))
            {
                result = result.Remove(p1, p2 - p1 + 1).Trim();
            }
            return result;
        }


        public static string GetSortNameExcludeBracketed(this string name)
        {
            string result = ExcludeBracketed(name, '[', ']');
            return GetSortName(result);
        }
    }

}
